二、核心基础:内存管理
2.1 物理内存布局(DDR 整体划分)
内存分配是应用开发的基础,本章主要介绍 TacoAI 的内存管理机制。
以板载 16GiB DDR 为例,SDK 将总共 16384MiB 地址空间划分成 3 个工作区:
| 内存区域 | 物理地址范围 | 容量 | 管理方式 |
|---|---|---|---|
| Linux 系统内存区 | 0x1,0000,0000 ~ 0x1,FFFF,FFFF | 4GiB | 自动管理,不可配置 |
| 媒体专用内存区 | 0x2,0000,0000 ~ 0x3,FFFF,FFFF | 8GiB | 用户可配置 |
| NPU 专用内存区 | 0x4,0000,0000 ~ 0x4,FFFF,FFFF | 4GiB | 用户可配置 |
各内存区使用逻辑
- Linux 系统内存区:应用程序运行所需的进程、线程空间、堆空间(heap)都位于此区域
- 媒体专用内存区:主要用于缓存媒体数据,特指以帧为单位的音视频数据
- NPU 专用内存区:主要用于加载神经网络模型,以及在执行推理过程中缓存中间数据和推理结果
2.2 内存域模型与访存特性
SDK 在设计上将 DDR 内存按照用途划分为三个域(domain):
系统域(System Domain)
- 管理方式:由 Ubuntu 系统直接管理
- 用途:为操作系统本身以及各类应用程序提供运行环境和业务内存
- 示例:系统调用
malloc()接口返回的内存即位于系统域
媒体域(Media Domain)
- 管理方式:由媒体模块(tasys)直接管理
- 用途:主要用于存储音视频编解码业务所涉及的数据,包括压缩码流数据和解压后的帧数据等
NN 域(Neural Network Domain)
- 管理方式:由 NPU 驱动直接管理
- 用途:主要用于存储神经网络(NN)业务所涉及的数据,包括网络模型的指令流和权重数据,以及 NPU 工作时产生的临时数据等
2.2.1 访存特性差异
上述三个域除了名称不同之外,本质差异在于数据的存储方式和访存方式不同:
- EA65xx 芯片的 CPU 使用虚拟地址访问 DDR,这种虚拟地址与 NPU 硬件使用的虚拟地址不同
- 两者使用各自独立的内存分配器
- 虚拟地址在逻辑上是连续的,但是虚拟地址所对应的物理地址一般并不连续,而是以页为单位随机分布在所属的域上
- 如果数据存储在系统域,则除了 CPU 外其它硬件难以寻址,除非该硬件也支持页表,可以逐页建立地址映射关系
系统域访存特性
- EA65xx 芯片的 CPU 配备了 MMU(Memory Management Unit)单元
- 运行在 CPU 上的程序使用虚拟地址访问 DDR 内存(称为 CPU 虚拟地址或系统域虚拟地址)
- 虚拟地址对应的物理地址以页(每页 4KB)为单位随机分布在系统域上
- CPU 访问内存需要通过 MMU 做地址映射
- CPU 以外的主控单元难以访问系统域 buffer 的数据
媒体域访存特性
- EA65xx 芯片中的媒体单元(包括视频编解码和 JPEG 编解码器)均没有配备 MMU 单元
- 媒体单元只能通过物理地址访问 DDR 内存,并且要求一帧数据必须是连续存储的(contiguous)
- SDK 规划了媒体域内存区专门用于存储音视频数据
- 媒体驱动(tasys)提供了将物理地址映射为 CPU 虚拟地址的接口
- NPU 驱动提供了将物理地址映射为 NPU 虚拟地址的接口
NN 域访存特性
- EA65xx 芯片的 NPU 配备了 MMU 单元
- NPU 硬件使用虚拟地址访问 DDR 内存(称为 NPU 虚拟地址或 NN 域虚拟地址)
- NPU 虚拟地址与 CPU 虚拟地址无关
2.2.2 数据访问解决方案
如果待推理的图像实际存储在系统域,NPU 不能使用 CPU 虚拟地址进行访问,SDK 支持两种解决方法:
方法一:拷贝方法
- 实现:在 taRuntime 接口内部将图像数据从系统域复制到 NN 域 buffer
- 访问方式:NPU 通过 NN 域虚拟地址访问图像
- 缺点:消耗 CPU 和 DDR 带宽资源
- 推荐度:不推荐作为正式产品方案
方法二:映射方法
- 实现:在 taRuntime 接口内部将系统域虚拟地址以内存页为单位逐页映射为 NN 域虚拟地址
- 缺点:当图像比较大时,操作耗时较多(约 20ms)
- 推荐度:不推荐作为正式产品方案
推荐方案
根据以上讨论,图像不宜存储在系统域内存区,而应存储在媒体域内存区。taRuntime 接口支持外部提供待推理图像的物理地址,接口内部将物理地址映射为 NN 域虚拟地址,这个操作开销较小。
2.3 tasys 内存介绍
2.3.1 tasys 简介与公共缓存池
- EA65xx 芯片上的硬件编解码单元和视频处理单元只能使用物理地址访问 DDR
- 使用 FFmpeg/OpenCV 库提供的硬件加速功能时,相关接口最终只能使用 tasys 模块分配的内存,不能使用
malloc()接口分配的系统域内存 - tasys 提供 alloc 接口,以便用户申请连续的物理内存块
- SDK 中的 tasys 模块提供了配置和创建公共缓存池的接口
- 用户可以为每个公共缓存池配置一批缓存块(VB,Video Buffer)
⚠️ 注意:
- 应用程序应在初始化阶段创建好各业务所需的缓存池,业务一旦开始运转,缓存池的配置就不能轻易变化。
2.3.2 tasys 公共缓存池配置
在板端运行时,/boot/firmware/ 目录下存在 taco_sys_memory_config.json 文件,用于配置 common pool 的 tasys 内存。修改 JSON 文件后重启板子生效。
如果想了解 tasys 的具体使用,参考 API 参考的「tasys 接口详解」章节。
{
"comm_pool": [
{
"blk_cnt": 24,
"blk_size": 4096,
"meta_size": 0,
"pool_name": "common_pool_0",
"remap_mode": 0,
"zone_name": "anonymous"
},
{
"blk_cnt": 4,
"blk_size": 98304,
"meta_size": 0,
"pool_name": "common_pool_1",
"remap_mode": 0,
"zone_name": "anonymous"
},
{
"blk_cnt": 4,
"blk_size": 196608,
"meta_size": 0,
"pool_name": "common_pool_2",
"remap_mode": 0,
"zone_name": "anonymous"
},
{
"blk_cnt": 4,
"blk_size": 393216,
"meta_size": 0,
"pool_name": "common_pool_3",
"remap_mode": 0,
"zone_name": "anonymous"
},
{
"blk_cnt": 60,
"blk_size": 614400,
"meta_size": 0,
"pool_name": "common_pool_4",
"remap_mode": 0,
"zone_name": "anonymous"
},
{
"blk_cnt": 4,
"blk_size": 786432,
"meta_size": 0,
"pool_name": "common_pool_5",
"remap_mode": 0,
"zone_name": "anonymous"
},
{
"blk_cnt": 256,
"blk_size": 3133440,
"meta_size": 0,
"pool_name": "common_pool_6",
"remap_mode": 0,
"zone_name": "anonymous"
},
{
"blk_cnt": 256,
"blk_size": 3137536,
"meta_size": 0,
"pool_name": "common_pool_7",
"remap_mode": 0,
"zone_name": "anonymous"
},
{
"blk_cnt": 68,
"blk_size": 6266880,
"meta_size": 0,
"pool_name": "common_pool_8",
"remap_mode": 0,
"zone_name": "anonymous"
}
],
"max_pool_cnt": 1024
}
2.4 高性能内存访问策略
2.4.1 缓存一致性问题
典型应用场景:
通过 OpenCV 或 TacoCV 接口在图像上绘制图形和文字,这部分功能是 CPU 借助虚拟地址访问 DDR 中的图像数据实现的。
性能优化建议:
- 虚拟地址是否映射为 cacheable 类型对绘图效率影响很大
- 建议在创建公共缓存池时,将 POOL/VB 的映射类型配置为
CACHEABLE
缓存一致性要求:
当 CPU 完成绘图操作后,用户应调用 tasys 模块提供的 taco_sys_cache_flush() 接口将 CPU 缓存中的数据主动同步到 DDR 中,否则 DDR 中的数据可能还是旧的,这就是所谓的 缓存一致性(cache coherency)问题。
2.4.2 关于零拷贝
PC 平台与 EA65xx 平台差异
| 平台 | 内存使用方式 |
|---|---|
| PC 平台 | 通过 malloc() 从操作系统申请 buffer,加载数据后提交给 FFmpeg 进行编解码 |
| EA65xx 平台 | 由于硬件约束,对 buffer 的使用方式需要变化 |
硬件访问限制
EA65xx 芯片的硬件单元无法直接访问系统域 buffer,因此:
- 如果输入数据位于系统域,SDK 必须把数据拷贝到媒体域才能交给硬件处理
- 这种拷贝会消耗 CPU 和 DDR 资源
零拷贝(Zero Copy)方案
SDK 对 FFmpeg 使用的 AVFrame 和 AVPacket 等结构体进行了扩展:
- 使用硬件加速功能时,用户可以提供媒体域 buffer 的物理地址以便硬件直接处理
- 如果用户提供的是系统域 buffer 的虚拟地址,FFmpeg 接口内部会自动申请媒体域 buffer 并执行一次拷贝
性能对比
两种工作方式在以下方面存在区别:
- DDR 带宽消耗
- CPU 负载
- 接口延迟
- 最高帧率
- buffer 数量
推荐:建议用户优先采用 零拷贝方式 以获得最佳性能。